package com.ikun.admin.modules.gen.iservice.impl;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ikun.admin.common.utils.GenerateCode;
import com.ikun.admin.modules.gen.constant.GenConstant;
import com.ikun.admin.modules.gen.entity.CodeConfig;
import com.ikun.admin.modules.gen.entity.GenerateTable;
import com.ikun.admin.modules.gen.entity.Table;
import com.ikun.admin.modules.gen.entity.TableEntity;
import com.ikun.admin.modules.gen.iservice.ICustomGenerateCodeService;
import com.ikun.admin.modules.gen.mapper.GenerateTableMapper;
import com.ikun.admin.modules.gen.service.CodeConfigService;
import com.ikun.admin.modules.gen.service.TableEntityService;
import com.ikun.admin.modules.gen.service.TableService;
import com.ikun.admin.modules.gen.vo.CreateTableAndCodeParamVo;
import com.ikun.common.exception.MyException;
import com.ikun.common.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName CustomGenerateCodeImpl
 * @Description:
 * @CreateDate: 2024/4/13 1:50
 */
@Service
public class ICustomGenerateCodeServiceImpl implements ICustomGenerateCodeService {

    private final DruidDataSource druidDataSource;
    @Autowired
    private TableService tableService;
    @Autowired
    private TableEntityService tableEntityService;
    @Autowired
    private GenerateTableMapper generateCodeMapper;
    @Autowired
    private CodeConfigService codeConfigService;

    @Autowired
    public ICustomGenerateCodeServiceImpl(DruidDataSource druidDataSource) {
        this.druidDataSource = druidDataSource;
    }

    //
    @Override
    @Transactional
    public Result<String> generateTableAndCode(CreateTableAndCodeParamVo createTableAndCodeParamVo) {
        Boolean generateCode = createTableAndCodeParamVo.getGenerateCode();
        List<Long> tableIdList = createTableAndCodeParamVo.getTableIdList();
        List<Table> tableList = tableService.list(new QueryWrapper<Table>().lambda().in(Table::getId, tableIdList));

        if (Objects.isNull(tableList) || tableList.size() == 0) {
            throw new MyException("未找到表");
        }
        Map<Long, Table> tableMap = tableList.stream().collect(Collectors.toMap(Table::getId, item -> item, (pre, next) -> next));
        List<TableEntity> tableEntityList = tableEntityService.list(new QueryWrapper<TableEntity>().lambda().in(TableEntity::getTableId, tableIdList));
        Set<Long> tableEntityTableIdSet = tableEntityList.stream().map(TableEntity::getTableId).collect(Collectors.toSet());
        Set<Long> noTableEntityIdSet = tableIdList.stream().filter(tableId -> !tableEntityTableIdSet.contains(tableId)).collect(Collectors.toSet());
        if (noTableEntityIdSet.size() > 0) {
            StringBuilder message = new StringBuilder("你还有如下表:");
            for (Long tableId : noTableEntityIdSet) {
                Table table = tableMap.get(tableId);
                message.append(table.getTableName()).append(",");
            }
            String messageStr = message.substring(0, message.length() - 1) + "。未设置属性";
            throw new MyException(messageStr);
        }

        //建表
        this.generateTable(tableList, tableEntityList);

        tableService.update(new UpdateWrapper<Table>().lambda().in(Table::getId, tableIdList)
                .set(Table::getStatus, GenConstant.TABLE_STATUS_GEN_TABLE));

        //创建代码
        if (generateCode) {
            Set<Long> configIdSet = tableList.stream().map(table -> table.getCodeConfigId()).collect(Collectors.toSet());
            if (Objects.isNull(configIdSet) || configIdSet.size() > 1) {
                throw new MyException("未配置生成策略 或者 存在多个代码生成配置,请分批次生成");
            }
            CodeConfig codeConfig = codeConfigService.getOne(new QueryWrapper<CodeConfig>().lambda().in(CodeConfig::getId, configIdSet));
            String result = GenerateCode.generateCode(codeConfig, druidDataSource, tableList);

            //修改状态
            tableService.update(new UpdateWrapper<Table>().lambda().in(Table::getId, tableIdList)
                    .set(Table::getStatus, GenConstant.TABLE_STATUS_GEN_CODE));
        }

        //操作成功
        return new Result<String>().success("操作成功");
    }

    @Override
    public Result<String> generateCode(List<Long> tableIdList) {
        // 校验...
        if (Objects.isNull(tableIdList) || tableIdList.size() == 0) {
            throw new MyException("未知的数据");
        }
        // 查询状态
        List<Table> tableList = tableService.list(new QueryWrapper<Table>().lambda().in(Table::getId, tableIdList));
        // 任意一个不满足 状态 为 1
        boolean flag = tableList.stream().anyMatch(item -> !Objects.equals(item.getStatus(), GenConstant.TABLE_STATUS_GEN_TABLE));
        if (flag) {
            throw new MyException("存在状态不符的表，请仔细查看,多看一眼就会爆炸~~");
        }
        //生成代码
        String result = this.generate(tableList);
        //修改状态
        tableService.update(new UpdateWrapper<Table>().lambda().in(Table::getId, tableIdList)
                .set(Table::getStatus, GenConstant.TABLE_STATUS_GEN_CODE));
        return new Result<String>().success(result);
    }

    public String generate(List<Table> tableList) {
        Set<Long> configIdSet = tableList.stream().map(table -> table.getCodeConfigId()).collect(Collectors.toSet());
        if (Objects.isNull(configIdSet) || configIdSet.size() > 1) {
            throw new MyException("为配置生成策略 或者 存在多个代码生成配置,请分批次生成");
        }
        CodeConfig codeConfig = codeConfigService.getOne(new QueryWrapper<CodeConfig>().lambda().in(CodeConfig::getId, configIdSet));
        return GenerateCode.generateCode(codeConfig, druidDataSource, tableList);
    }

    /**
     * 创建表
     * @param tableList
     * @param tableEntityList
     */
    public void generateTable(List<Table> tableList, List<TableEntity> tableEntityList) {

        Map<Long, List<TableEntity>> tableEntityMap = tableEntityList.stream().collect(Collectors.groupingBy(TableEntity::getTableId));

        for (Table table : tableList) {

            Optional<Table> optionalTable = Optional.ofNullable(table);

            optionalTable.flatMap(t -> Optional.ofNullable(t.getId())).ifPresent(tableId -> {
                Optional<List<TableEntity>> optionalTableEntityList = Optional.ofNullable(tableEntityMap.get(tableId));
                optionalTableEntityList.ifPresent(tableEntities -> {
                    GenerateTable generateTable = new GenerateTable();
                    generateTable.setTable(table);
                    generateTable.setTableEntityList(tableEntities);
                    generateCodeMapper.generateTable(table, tableEntities);
                });
            });
        }

    }
}
